/**
 *******************************************************************************
 * @file    bsp_usart.c
 * @version V1.0
 * @date    2013-xx-xx
 * @brief   此文件用于配置USART2，提供串口数据的发送与接收功能
 *******************************************************************************
 * @attention
 *
 * 硬件平台：基于STM32 F103系列芯片
 * 在线交流： http://www.firebbs.cn
 * 购买链接： https://fire-stm32.taobao.com
 *
 *******************************************************************************
 */

#include <string.h> // 引入字符串处理库
#include <stdio.h>  // 引入标准输入输出库
#include "bsp_usart2.h" // 引入USART2的头文件
#include "bsp_usart.h"  // 引入USART的头文件

/**
 * @brief 配置USART2的硬件参数和GPIO
 * 
 * 此函数完成USART2的初始化，包括设置波特率、数据位、停止位、校验位及GPIO的配置。
 */
void USART2_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure; // GPIO初始化结构体
    USART_InitTypeDef USART_InitStructure; // USART初始化结构体

    // 打开GPIOA和USART2的时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); 

    // 将PA2配置为USART2的发送口（Tx），为复用推挽模式
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // GPIO速度为50MHz
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // 将PA3配置为USART2的接收口（Rx），为浮空输入
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // 配置USART2的工作参数
    USART_InitStructure.USART_BaudRate = 9600;                      // 配置波特率
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;                     // 数据字长为8位
    USART_InitStructure.USART_StopBits = USART_StopBits_1;                          // 停止位为1
    USART_InitStructure.USART_Parity = USART_Parity_No;                             // 不使用校验位
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 不使用硬件流控制
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;                 // 配置为收发模式
    USART_Init(USART2, &USART_InitStructure);                                       // 初始化USART2

    // 配置USART的中断优先级
    NVIC_InitTypeDef NVIC_InitStructure; // NVIC初始化结构体
    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; // USART2的中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 中断抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;        // 中断从优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;           // 开启中断
    NVIC_Init(&NVIC_InitStructure);                           // 初始化NVIC

    // 使能USART2的接收中断
    USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);

    // 使能USART2
    USART_Cmd(USART2, ENABLE);
}

// 存储USART2接收到的消息
static UsartRecvMsgType usart2_msg = {
    .finish = 0, // 是否接收到完整消息的标记
    .index = 0,  // 当前接收到的字符索引
    .buf = {'\0'} // 存储接收到的字符缓冲区
};

/**
 * @brief 获取USART2接收到的消息
 * @param mem 存储接收到消息的内存地址
 * @param len 内存长度
 * @return 接收到的消息长度
 */
u16 usart2_get_msg(char *mem, u16 len)
{
    u16 size = 0; // 消息长度
    if (usart2_msg.finish == 1) // 检查是否接收到完整消息
    {
        size = len > usart2_msg.index ? usart2_msg.index : len; // 取最小值
        memcpy(mem, usart2_msg.buf, size); // 拷贝消息到指定内存
    }
    return size; // 返回消息长度
}

/**
 * @brief 发送消息到USART2
 * @param msg 发送的消息
 */
void usart2_send_msg(const char *msg)
{
    while (*msg != '\0') // 循环直到消息结尾
    {
        // 发送一个字符到USART2
        USART_SendData(USART2, (uint8_t)*msg);

        // 等待数据发送完毕
        while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET)
            ;
        msg++; // 移动到下一个字符
    }
}

/**
 * @brief 清除USART2接收到的消息
 */
void usart2_clear_msg(void)
{
    usart2_msg.finish = 0; // 标记为未完成
    usart2_msg.index = 0;  // 重置索引
}

/**
 * @brief 接收一个字符，并判断是否接收完毕
 * @param c 接收到的字符
 */
void usart2_receive_str(u8 c)
{
    if (c == '\n') // 判断是否为换行符
        usart2_msg.finish = 1; // 标记为接收完成

    // 如果索引未达到最大长度，则保存字符
    if (usart2_msg.index < RECV_MAX_LEN - 1)
        usart2_msg.buf[usart2_msg.index++] = c;
}
